import { BridgeDirection, ProvidersType } from "./ChainProviderFactory";
import { Wallet as XrplWallet } from "xrpl";
import { Wallet as EvmWallet } from "ethers";
import { evmAddressToXrplAccount, xrplAccountToEvmAddress } from "../util/address-derivation";
import { ChainProvider } from "./ChainProvider";
import * as fs from "fs";
import { sleep } from "./utils";

export type Account = {
    pk: string;
    address: string;
    otherChainAddress: string;
    provider: ChainProvider;
};

export type Accounts = {
    source: Account;
    destination: Account;
};

export class AccountManager {
    evmPrivateKeys: string[] = [];
    constructor(private providers: ProvidersType) {
        try {
            const file = fs.readFileSync("./evm-private-keys.json");
            this.evmPrivateKeys = JSON.parse(file.toString());
        } catch (e) {}
    }

    createAccounts(direction: BridgeDirection): Accounts {
        const xrpWallet = XrplWallet.generate();
        const xrpAccount = {
            pk: xrpWallet.seed!,
            address: xrpWallet.address,
            otherChainAddress: xrplAccountToEvmAddress(xrpWallet.address),
        };

        const evmWallet = EvmWallet.createRandom();
        const evmAccount = {
            pk: evmWallet.privateKey,
            address: evmWallet.address,
            otherChainAddress: evmAddressToXrplAccount(evmWallet.address),
        };
        this.writeFundedPrivateKey(evmWallet.privateKey);

        if (direction === BridgeDirection.XRP_TO_EVM) {
            return {
                source: {
                    ...xrpAccount,
                    provider: this.providers[direction].source,
                },
                destination: {
                    ...evmAccount,
                    provider: this.providers[direction].destination,
                },
            };
        } else {
            return {
                source: {
                    ...evmAccount,
                    provider: this.providers[direction].source,
                },
                destination: {
                    ...xrpAccount,
                    provider: this.providers[direction].destination,
                },
            };
        }
    }

    async fundAccounts(accounts: Accounts, sourceAmount: number, destinationAmount: number): Promise<void> {
        const fundingPromises: Promise<void>[] = [];
        if (sourceAmount > 0) {
            fundingPromises.push(accounts.source.provider.fundAccount(accounts.source.pk, sourceAmount));
        }
        if (destinationAmount > 0) {
            fundingPromises.push(accounts.destination.provider.fundAccount(accounts.destination.pk, destinationAmount));
        }
        await Promise.all(fundingPromises);
    }

    writeFundedPrivateKey(pk: string) {
        this.evmPrivateKeys.push(pk);
        fs.writeFileSync("./evm-private-keys.json", JSON.stringify(this.evmPrivateKeys));
    }

    async refundAllUsedAccounts(): Promise<void> {
        let i = 0;
        for (const pk of this.evmPrivateKeys) {
            console.log(`Refunding [${i}/${this.evmPrivateKeys.length}] ${pk}`);
            this.providers[BridgeDirection.EVM_TO_XRP].source.refundAccount(pk);
            this.providers[BridgeDirection.XRP_TO_EVM].source.refundAccount(pk);
            await sleep(0.5);
            i++;
        }
        console.log(`Refunded all used accounts`);
        fs.unlinkSync("./evm-private-keys.json");
    }
}
